/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h" // 引入 FreeRTOS 信号量头文件

/* Xilinx includes. */
#include "xil_printf.h"
#include "xstatus.h" // 包含 XST_SUCCESS 等状态码

// 引入封装好的 VDMA 显示模块
#include "vdma_display.h"
// 引入 SMRS 模块
#include "smrs.h"

// 引入兔子渲染模块
#include "demo1_bunny.h"

// --- 全局实例，以便任务函数可以访问 ---
VdmaDisplay g_vdma_display; // VDMA 显示模块实例
SmrsContext g_smrs_context; // SMRS 渲染调度模块实例

/*-----------------------------------------------------------*/
// 定义任务句柄
static TaskHandle_t xHdmiInitTaskHandle = NULL;
static TaskHandle_t xGpuRenderTaskHandle = NULL;

// 定义FreeRTOS队列，用于任务间通信，例如HDMI初始化完成后通知显示任务
static QueueHandle_t xHdmiReadyQueue = NULL; // 用于通知初始化完成

// 渲染任务的参数结构体
// 用于将 VdmaDisplay 和 SmrsContext 实例指针以及队列句柄传递给渲染任务
typedef struct {
    VdmaDisplay* vdma_display;
    SmrsContext* smrs_context;
    QueueHandle_t hdmi_ready_queue;
} GpuRenderTaskParams_t;

// 渲染任务的参数实例
static GpuRenderTaskParams_t xGpuRenderTaskParams;

/*-----------------------------------------------------------*/
// FreeRTOS 任务函数原型
static void vHdmiInitTask( void *pvParameters );
// vGpuRenderTask 的原型现在从 demo1_bunny.h 中获取

/*-----------------------------------------------------------*/
// FreeRTOS 静态内存分配 (如果 configSUPPORT_STATIC_ALLOCATION == 1)
#if (configSUPPORT_STATIC_ALLOCATION == 1)
// 为 HDMI 初始化任务定义静态内存
StackType_t xHdmiInitStack[ configMINIMAL_STACK_SIZE * 4 ];
StaticTask_t xHdmiInitBuffer;

// 为 GPU 渲染任务定义静态内存
StackType_t xGpuRenderStack[ configMINIMAL_STACK_SIZE * 8 ];
StaticTask_t xGpuRenderBuffer;

// 为 HDMI 就绪队列定义静态内存 (用于传递一个 int 信号)
uint8_t ucHdmiReadyQueueStorage[ sizeof( int ) * 2 ]; // 队列深度增加到2，确保两个任务都能收到
StaticQueue_t xStaticHdmiReadyQueue;
#endif


int main( void )
{
	xil_printf( "\r\n--- FreeRTOS HDMI Output Bunny Demo (Made by SDJU PanZiyu-221003710521) ---\r\r\n" );
	xil_printf( "  Compiled on: %s at %s\r\n", __DATE__, __TIME__);

	xil_printf( "  VDMA Output Resolution: %u x %u\r\n", VdmaDisplay_getOutputWidth(&g_vdma_display), VdmaDisplay_getOutputHeight(&g_vdma_display));
	xil_printf( "  HLS Render Resolution: %u x %u\r\n", VdmaDisplay_getHlsRenderWidth(&g_vdma_display), VdmaDisplay_getHlsRenderHeight(&g_vdma_display)); // 打印HLS渲染分辨率
	xil_printf( "  VDMA Expected Bytes per Pixel: %u (BGR)\r\n", VdmaDisplay_getBytesPerPixel(&g_vdma_display));
	xil_printf( "  HLS IP Writes Bytes per Pixel: %u (BGRX)\r\n", VdmaDisplay_getHlsBytesPerPixel(&g_vdma_display));
	xil_printf( "  Using Triple Buffering with %u frames.\r\n", VDMA_NUM_FRAME_BUFFERS);
	xil_printf( "  GPU Params Buffer Base Address: 0x%x\r\n", (unsigned int)SMRS_GPU_PARAMS_BUFFER_BASE_ADDR);
	xil_printf( "  GPU ZBuffer Base Address: 0x%x\r\r\n", (unsigned int)SMRS_GPU_ZBUFFER_BASE_ADDR); // ZBuffer 信息
	xil_printf( "  Bunny Vertices: %u, Triangles: %u\r\r\n", BUNNY_NUM_VERTICES, BUNNY_NUM_TRIANGLES);
	xil_printf( "  HLS IP Max Triangles per Batch: %u\r\n", SMRS_MAX_NUM_TRIANGLES); // Max Triangles
	xil_printf( "  HLS IP Words per Triangle: %u\r\n", SMRS_NUM_AXI_WORDS_PER_PACKET); // Words per Triangle
	
	// 创建用于任务间通信的队列 (队列深度为 2，传递一个 int，确保两个任务都能收到)
#if ( configSUPPORT_STATIC_ALLOCATION == 0 )
    xHdmiReadyQueue = xQueueCreate( 2, sizeof( int ) );
#else
    xHdmiReadyQueue = xQueueCreateStatic( 2, sizeof( int ), ucHdmiReadyQueueStorage, &xStaticHdmiReadyQueue);
#endif
    configASSERT( xHdmiReadyQueue != NULL );

    // 设置渲染任务的参数
    xGpuRenderTaskParams.vdma_display = &g_vdma_display;
    xGpuRenderTaskParams.smrs_context = &g_smrs_context;
    xGpuRenderTaskParams.hdmi_ready_queue = xHdmiReadyQueue;


    // 统一任务创建代码
#if ( configSUPPORT_STATIC_ALLOCATION == 0 )
    // 动态创建任务
    xTaskCreate( vHdmiInitTask, "HDMI Init", configMINIMAL_STACK_SIZE * 4, NULL, tskIDLE_PRIORITY + 3, &xHdmiInitTaskHandle );
    // GPU Render Task 栈空间调整
    xTaskCreate( vGpuRenderTask, "GPU Render", configMINIMAL_STACK_SIZE * 8, (void*)&xGpuRenderTaskParams, tskIDLE_PRIORITY + 2, &xGpuRenderTaskHandle );

#else
    xil_printf( "  Using static memory for FreeRTOS tasks and queues.\r\n" );
    // 静态创建任务
    xHdmiInitTaskHandle = xTaskCreateStatic( vHdmiInitTask, "HDMI Init", configMINIMAL_STACK_SIZE * 4, NULL, tskIDLE_PRIORITY + 3, xHdmiInitStack, &xHdmiInitBuffer );
    configASSERT( xHdmiInitTaskHandle != NULL );

    // GPU Render Task 栈空间调整
    xGpuRenderTaskHandle = xTaskCreateStatic( vGpuRenderTask, "GPU Render", configMINIMAL_STACK_SIZE * 8, (void*)&xGpuRenderTaskParams, tskIDLE_PRIORITY + 2, xGpuRenderStack, &xGpuRenderBuffer );
    configASSERT( xGpuRenderTaskHandle != NULL );
#endif

    // 启动 FreeRTOS 调度器
    vTaskStartScheduler();
    
    // 如果调度器启动失败（例如，内存不足），程序将执行到这里
    xil_printf( "Error: Scheduler failed to start or tasks terminated unexpectedly.\r\r\n" );
    for( ;; ); // main 函数不应该返回
}

// HDMI 初始化任务实现：负责 VDMA 和 HDMI 链路的一次性设置
static void vHdmiInitTask( void *pvParameters )
{
    int received_signal = 0;
    ( void ) pvParameters; // 消除未使用的参数警告

    xil_printf("\r\n[HDMI Init Task]: Starting VDMA initialization.\r\n");
    
    // 调用封装的 VDMA 初始化函数
    VdmaDisplay_init_struct(&g_vdma_display); // 首先初始化结构体成员，包括信号量句柄
    int status = VdmaDisplay_init(&g_vdma_display); // 然后创建信号量并初始化VDMA
    
    if (status != XST_SUCCESS) {
        xil_printf("[HDMI Init Task]: FATAL ERROR: VDMA initialization failed! Status=%d.\r\n", status);
        xil_printf("                 System in degraded state. HDMI output will not function.\r\n");
        for( ;; ) {
            vTaskDelay( portMAX_DELAY ); // 永久阻塞，不消耗CPU
        }
    }
    xil_printf("[HDMI Init Task]: VDMA display initialized successfully.\r\n");

    // 初始化 SMRS 模块
    status = Smrs_Init(&g_smrs_context, &g_vdma_display);
    if (status != SMRS_SUCCESS) {
        xil_printf("[HDMI Init Task]: FATAL ERROR: SMRS module initialization failed! Status=%d.\r\n", status);
        for( ;; ) { vTaskDelay( portMAX_DELAY ); }
    }
    xil_printf("[HDMI Init Task]: SMRS module initialized successfully.\r\n");

    // VDMA 和 SMRS IP 初始化成功后，发送信号通知其他任务
    // 因为队列深度是2，所以发送两次，确保两个任务都能收到
    if (xQueueSend( xHdmiReadyQueue, &received_signal, portMAX_DELAY ) != pdPASS) { // Use received_signal (value 0) or any constant int.
        xil_printf("[HDMI Init Task]: ERROR: Failed to send HDMI ready signal (1) to queue.\r\n");
    }
    // 第二次发送，确保 GPU Render Task 可以接收到
    if (xQueueSend( xHdmiReadyQueue, &received_signal, portMAX_DELAY ) != pdPASS) { // Use received_signal (value 0) or any constant int.
        xil_printf("[HDMI Init Task]: ERROR: Failed to send HDMI ready signal (2) to queue.\r\n");
    } else {
        xil_printf("[HDMI Init Task]: Signals sent to GPU Render (and potentially other) Tasks.\r\n");
    }

    // HDMI 初始化任务完成其工作，可以安全地删除自身。
    xil_printf("[HDMI Init Task]: Initialization complete, deleting task.\r\n");
    vTaskDelete( NULL ); // 删除当前任务
}
